package org.linlinjava.litemall.wx.web;

import cn.binarywang.wx.miniapp.api.WxMaMsgService;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.impl.WxMaMsgServiceImpl;
import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage;
import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.BaseWxPayResult;

import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.util.SignUtils;
import com.google.common.collect.Lists;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.ognl.IntHashMap;
import org.apache.log4j.Logger;
import org.linlinjava.litemall.core.util.JacksonUtil;
import org.linlinjava.litemall.db.domain.*;
import org.linlinjava.litemall.db.service.LitemallOrderGoodsService;
import org.linlinjava.litemall.db.service.LitemallOrderService;
import org.linlinjava.litemall.db.service.LitemallProductService;
import org.linlinjava.litemall.db.service.LitemallUserService;
import org.linlinjava.litemall.core.util.ResponseUtil;
import org.linlinjava.litemall.db.service.distribution.DisMemberInfoService;
import org.linlinjava.litemall.db.util.DateTools;
import org.linlinjava.litemall.db.util.OrderHandleOption;
import org.linlinjava.litemall.db.util.OrderUtil;
import org.linlinjava.litemall.wx.annotation.LoginUser;
import org.linlinjava.litemall.wx.config.WeixinConfig;
import org.linlinjava.litemall.wx.dao.PayRequestPayment;
import org.linlinjava.litemall.wx.util.IdUtil;
import org.linlinjava.litemall.wx.util.MD5;
import org.linlinjava.litemall.wx.util.SendMsgUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.web.bind.annotation.*;
import sun.reflect.annotation.ExceptionProxy;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.*;

@RestController
@RequestMapping("/wx/pay")
public class WxPayController {
    private Logger logger = Logger.getLogger(WxPayController.class);

    @Autowired
    private LitemallOrderService orderService;
    @Autowired
    private LitemallOrderGoodsService orderGoodsService;
    @Autowired
    private LitemallUserService userService;
    @Autowired
    private WxPayService wxService;
    @Autowired
    private LitemallProductService productService;
    @Autowired
    private PlatformTransactionManager txManager;

    @Autowired
    private WxMaService wxMaService;
    @Autowired
    private DisMemberInfoService memberService;


    /**
     * 获取支付的请求参数
     */
    @RequestMapping("prepay")
    public Object payPrepay(@LoginUser Integer userId, @RequestParam("orderId") Integer orderId, HttpServletRequest request) {
        if (userId == null) {
            return ResponseUtil.fail401();
        }
        if (orderId == null) {
            return ResponseUtil.fail402();
        }

        LitemallOrder order = orderService.findById(orderId);
        List<LitemallOrderGoods> list = orderGoodsService.queryByOid(orderId);
        LitemallUser user = userService.findById(userId);
        if (user.getWeixinOpenid() == null) {
            return ResponseUtil.fail(403, "用户openid不存在");
        }
        if (order == null) {
            return ResponseUtil.fail(403, "订单不存在");
        }

        // return ResponseUtil.ok("模拟支付成功");
        if (!OrderUtil.STATUS_CREATE.equals(order.getPayStatus())) {
            return ResponseUtil.fail(403, "订单已被处理，请不要重复操作");
        }

        WxPayUnifiedOrderRequest wxPayUnifiedOrderRequest = new WxPayUnifiedOrderRequest();
        WxPayUnifiedOrderResult wxPayUnifiedOrderResult = null;
        //页面返回元素
        PayRequestPayment payment = new PayRequestPayment();
        try {
            StringBuffer sb = new StringBuffer();
            sb.append("AR小哈早教机器人--");
            for (LitemallOrderGoods good : list) {
                sb.append(good.getGoodsName());
                sb.append(",");
            }
            wxPayUnifiedOrderRequest.setMchId(WeixinConfig.WX_MchId);
            wxPayUnifiedOrderRequest.setBody(sb.substring(0, sb.length() - 1));
            wxPayUnifiedOrderRequest.setOutTradeNo(order.getOrderSn());
            wxPayUnifiedOrderRequest.setTotalFee(order.getActualPrice().multiply(new BigDecimal(100)).intValue());
            wxPayUnifiedOrderRequest.setSpbillCreateIp(request.getRemoteAddr());
            wxPayUnifiedOrderRequest.setNotifyUrl(WeixinConfig.NOTIFY_URL);
            wxPayUnifiedOrderRequest.setTradeType("JSAPI");
            wxPayUnifiedOrderRequest.setOpenid(user.getWeixinOpenid());

            wxPayUnifiedOrderResult = wxService.unifiedOrder(wxPayUnifiedOrderRequest);

            payment.setNonceStr(wxPayUnifiedOrderResult.getNonceStr());
            payment.setPackageStr("prepay_id=" + wxPayUnifiedOrderResult.getPrepayId());
            payment.setSignType("MD5");
            payment.setTimeStamp(System.currentTimeMillis() + "");

            Map<Object, Object> map = new HashMap<>();
            map.put("appId", wxPayUnifiedOrderRequest.getAppid());
            map.put("timeStamp", payment.getTimeStamp());
            map.put("nonceStr", payment.getNonceStr());
            map.put("package", payment.getPackageStr());
            map.put("signType", "MD5");

            String sign = arraySign(map, WeixinConfig.WX_MchKey);
            payment.setPaySign(sign);
            order.setPayId(wxPayUnifiedOrderResult.getPrepayId());
            orderService.update(order);


        } catch (WxPayException e) {
            e.printStackTrace();
            return ResponseUtil.fail(403, "支付失败");
        }


        return ResponseUtil.ok(payment);


    }

    /**
     * 微信订单回调接口
     */
    @RequestMapping(value = "/notify", method = RequestMethod.POST)
    public Object notify(HttpServletRequest request, HttpServletResponse response) {

        LitemallOrder order = new LitemallOrder();
        try {
            String xmlResult = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());
            WxPayOrderNotifyResult result = wxService.parseOrderNotifyResult(xmlResult);
            // 结果正确
            String orderId = result.getOutTradeNo();
            String tradeNo = result.getTransactionId();
            String totalFee = BaseWxPayResult.fenToYuan(result.getTotalFee());
            System.out.println("notify:" + orderId);
            order = orderService.queryByOrderSn(orderId);
            order.setOrderStatus(OrderUtil.STATUS_PAY);
            order.setPayStatus(OrderUtil.STATUS_PAY);
            order.setPayTime(LocalDateTime.now());
            orderService.update(order);
            //自己处理订单的业务逻辑，需要判断订单是否已经支付过，否则可能会重复调用
            /*WxMaMsgService msgService = new WxMaMsgServiceImpl();
            WxMaKefuMessage message = new WxMaKefuMessage();
            message.setContent("ceshi");
            message.setTitle("收获通知");
            message.setDescription("描述");
            message.setMsgType("text");
            message.setToUser("oiR0E5lYOnVCcplWorxthB-hLE4Y");
            WxMaMsgService msgService.sendKefuMsg(message);*/
/**
 * 消息推送
 */
           /* wxMaService.getMsgService().sendTemplateMsg(WxMaTemplateMessage.builder()
                    .templateId("T3Dj6debK1OucsA2kCwu2_vWnTkbP5ZU8I930xFZCDc")
                    .formId("prepay_id=wx211800456145636c66712c220692354301")
                    .data(Lists.newArrayList(
                            new WxMaTemplateMessage.Data("keyword1", "339208499", "#173177"),
                            new WxMaTemplateMessage.Data("keyword2", "100", "#173177"),
                            new WxMaTemplateMessage.Data("keyword3", "20180521", "#173177"),
                            new WxMaTemplateMessage.Data("keyword4", "好玩的", "#173177")
                    ))
                    .toUser("oiR0E5lYOnVCcplWorxthB-hLE4Y")
                    .build());*/

        } catch (Exception e) {
            logger.error("微信回调结果异常,异常原因{}", e);
            return WxPayNotifyResponse.fail(e.getMessage());
        }
        try {
            String content = "{\"consignee\":\"" + order.getConsignee() + "\",\"number\":\"" + order.getMobile() + "\",\"price\":\"" + order.getActualPrice() + "\"}";
            SendMsgUtil.sendSmsByAliDayu(content);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return WxPayNotifyResponse.success("处理成功!");
    }

    /**
     * 客户订单退款申请
     */
    @RequestMapping("preRefund")
    public Object preRefund(@LoginUser Integer userId, @RequestBody LitemallOrder order) {
        if (userId == null) {
            return ResponseUtil.unlogin();
        }
        if (order.getId() == null) {
            return ResponseUtil.badArgument();
        }

        order = orderService.findById(order.getId());
        if (order == null) {
            return ResponseUtil.badArgument();
        }
        if (!order.getUserId().equals(userId)) {
            return ResponseUtil.badArgumentValue();
        }

        OrderHandleOption handleOption = OrderUtil.build(order);
        if (!handleOption.isRefund()) {
            return ResponseUtil.fail(403, "订单不能取消");
        }
        try {
            order.setOrderStatus(OrderUtil.STATUS_REFUNDING);
            orderService.update(order);
        } catch (Exception ex) {
            logger.error("系统内部错误", ex);
            return ResponseUtil.fail(403, "订单退款失败");
        }
        return ResponseUtil.ok();

    }

    /**
     * 订单退款请求
     */
    @RequestMapping("refund")
    public Object refund(@RequestBody LitemallOrder order) {

        if (order.getId() == null) {
            return ResponseUtil.badArgument();
        }

        order = orderService.findById(order.getId());
        if (order == null) {
            return ResponseUtil.badArgument();
        }

        OrderHandleOption handleOption = OrderUtil.build(order);
        if (!handleOption.isRefund()) {
            logger.error("取消订单：" + handleOption.isRefund());
            return ResponseUtil.fail(403, "订单不能取消");
        }

        // 开启事务管理
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        TransactionStatus status = txManager.getTransaction(def);
        try {
            // 退款操作
            WxPayRefundRequest request = new WxPayRefundRequest();
            request.setOutTradeNo(order.getOrderSn());
            request.setOutRefundNo(IdUtil.getId());
            request.setTotalFee(order.getActualPrice().multiply(new BigDecimal(100)).intValue());
            //微信收取0.6%的费用  这里扣除
            BigDecimal refountFee = order.getActualPrice();
            if(refountFee.compareTo(new BigDecimal(1))>0){
                request.setRefundFee((refountFee.multiply(new BigDecimal(99.4))).intValue());
            }else{
                request.setRefundFee((refountFee.multiply(new BigDecimal(100))).intValue());
            }

            WxPayRefundResult refund = wxService.refund(request);
            //退款成功
            if ("SUCCESS".equals(refund.getResultCode())) {
                order.setRefundId(refund.getRefundId());
                order.setRefundTime(LocalDateTime.now());
                // 设置订单取消状态
                order.setOrderStatus(OrderUtil.STATUS_REFUND);
                orderService.update(order);
                // 商品货品数量增加
                List<LitemallOrderGoods> orderGoodsList = orderGoodsService.queryByOid(64);
                for (LitemallOrderGoods orderGoods : orderGoodsList) {
                    Integer productId = orderGoods.getProductId();
                    LitemallProduct product = productService.findById(productId);
                    Integer number = product.getGoodsNumber() + orderGoods.getNumber();
                    product.setGoodsNumber(number);
                    productService.updateById(product);
                }
            } else {
                logger.error("微信退款失败：Code:" + refund.getErrCode() + ",Des:" + refund.getErrCodeDes());
                return ResponseUtil.fail(403, "订单退款失败");
            }
        } catch (Exception ex) {
            txManager.rollback(status);
            logger.error("系统内部错误", ex);
            return ResponseUtil.fail(403, "订单退款失败");
        }
        txManager.commit(status);

        return ResponseUtil.ok();

    }

    public static String arraySign(Map<Object, Object> params, String paySignKey) {
        boolean encode = false;
        Set<Object> keysSet = params.keySet();
        Object[] keys = keysSet.toArray();
        Arrays.sort(keys);
        StringBuffer temp = new StringBuffer();
        boolean first = true;
        for (Object key : keys) {
            if (first) {
                first = false;
            } else {
                temp.append("&");
            }
            temp.append(key).append("=");
            Object value = params.get(key);
            String valueString = "";
            if (null != value) {
                valueString = value.toString();
            }
            if (encode) {
                try {
                    temp.append(URLEncoder.encode(valueString, "UTF-8"));
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
            } else {
                temp.append(valueString);
            }
        }
        temp.append("&key=");
        temp.append(paySignKey);
        System.out.println(temp.toString());
        String packageSign = MD5.getMessageDigest(temp.toString());
        return packageSign;
    }

    public static void main(String[] args) {
        System.out.println(new BigDecimal(0.1).multiply(new BigDecimal(99.4)).intValue());
        System.out.println((int)(new BigDecimal(0.1).intValue() * 99.4));


    }

}